home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / hAWK project / AWK Source / BUILTIN.C < prev    next >
Text File  |  1994-12-22  |  23KB  |  1,063 lines

  1. /*
  2.  * builtin.c - Builtin functions and various utility procedures
  3.  */
  4.  
  5. /* Copyright © 1986, 1988, 1989 1991 the Free Software Foundation, Inc.
  6.  *         This file is part of GAWK, the GNU implementation of the
  7.  * AWK Progamming Language, modified for the Macintosh (also called hAWK).
  8.  *         GAWK is free software; you can redistribute or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 1, or any later version.
  11.  *         GAWK is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14.  * GNU General Public License for more details.
  15.  *         You should have received a copy of the GNU General Public License
  16.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  17.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  * Modified for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  19.  */
  20.  
  21. #include "AWK.H"
  22.  
  23. extern short srandom(unsigned x );
  24. extern char  *initstate(unsigned seed, char *arg_state, short n );
  25. extern char  *setstate(char *arg_state );
  26. extern long random(void);
  27.  
  28. extern char    *gcvt(double value, short digits, char *buff);
  29.  
  30. /* Mac version only: extension function to diagnose C token-type
  31. of user-defined top level terms. Used in do_lookup() below. */
  32. short InDictionary(char *tokenName);
  33.  
  34. extern NODE **fields_arr;
  35.  
  36. /* BUILTIN.C */
  37. NODE *do_exp(NODE *tree);
  38. NODE *do_index(NODE *tree);
  39. NODE *do_int(NODE *tree);
  40. NODE *do_length(NODE *tree);
  41. NODE *do_lookup(NODE *tree);
  42. NODE *do_log(NODE *tree);
  43. NODE *do_sprintf(NODE *tree);
  44. void do_printf(NODE *tree);
  45. NODE *do_sqrt(NODE *tree);
  46. NODE *do_substr(NODE *tree);
  47. NODE *do_system(NODE *tree);
  48. void do_print(register NODE *tree);
  49. NODE *do_tolower(NODE *tree);
  50. NODE *do_toupper(NODE *tree);
  51. static void get_one(NODE *tree, NODE **res);
  52. static void get_two(NODE *tree, NODE **res1, NODE **res2);
  53. static short get_three(NODE *tree, NODE **res1, NODE **res2, NODE **res3);
  54. short a_get_three(NODE *tree, NODE **res1, NODE **res2, NODE **res3);
  55. void print_simple(NODE *tree, FILE *fp);
  56. NODE *do_atan2(NODE *tree);
  57. NODE *do_sin(NODE *tree);
  58. NODE *do_cos(NODE *tree);
  59. NODE *do_rand(NODE *tree);
  60. NODE *do_srand(NODE *tree);
  61. NODE *do_match(NODE *tree);
  62. static NODE *sub_common(NODE *tree, short global);
  63. NODE *do_gsub(NODE *tree);
  64. NODE *do_sub(NODE *tree);
  65.  
  66. /* Builtin functions */
  67. NODE *do_exp(NODE *tree)
  68. {
  69.     NODE *tmp;
  70.     double d, res;
  71.     /*double exp();*/
  72.  
  73.     get_one(tree, &tmp);
  74.     d = force_number(tmp);
  75.     free_temp(tmp);
  76.     errno = 0;
  77.     res = exp(d);
  78.     if (errno == ERANGE)
  79.         warning("exp argument %g is out of range", d);
  80.     return tmp_number((AWKNUM) res);
  81. }
  82.  
  83. NODE *do_index(NODE *tree)
  84. {
  85.     NODE *s1, *s2;
  86.     register char *p1, *p2;
  87.     register short l1, l2;
  88.     long ret;
  89.  
  90.  
  91.     get_two(tree, &s1, &s2);
  92.     force_string(s1);
  93.     force_string(s2);
  94.     p1 = s1->stptr;
  95.     p2 = s2->stptr;
  96.     l1 = s1->stlen;
  97.     l2 = s2->stlen;
  98.     ret = 0;
  99.     if (/*! strict && */ IGNORECASE_node->var_value->numbr != 0.0) {
  100.         while (l1) {
  101.             if (casetable[*p1] == casetable[*p2]
  102.                 && strncasecmp(p1, p2, l2) == 0) {
  103.                 ret = 1 + s1->stlen - l1;
  104.                 break;
  105.             }
  106.             l1--;
  107.             p1++;
  108.         }
  109.     } else {
  110.         while (l1) {
  111.             if (STREQN(p1, p2, l2)) {
  112.                 ret = 1 + s1->stlen - l1;
  113.                 break;
  114.             }
  115.             l1--;
  116.             p1++;
  117.         }
  118.     }
  119.     free_temp(s1);
  120.     free_temp(s2);
  121.     return tmp_number((AWKNUM) ret);
  122. }
  123.  
  124. NODE *do_int(NODE *tree)
  125. {
  126.     NODE *tmp;
  127.     /*double floor();*/
  128.     double d;
  129.  
  130.     get_one(tree, &tmp);
  131.     d = floor((double)force_number(tmp));
  132.     free_temp(tmp);
  133.     return tmp_number((AWKNUM) d);
  134. }
  135.  
  136. NODE *do_length(NODE *tree)
  137. {
  138.     NODE *tmp;
  139.     short len;
  140.  
  141.     get_one(tree, &tmp);
  142.     len = force_string(tmp)->stlen;
  143.     free_temp(tmp);
  144.     return tmp_number((AWKNUM) len);
  145. }
  146.  
  147. NODE *do_lookup(NODE *tree)
  148. {
  149.     NODE *tmp;
  150.     short result;
  151.  
  152.     get_one(tree, &tmp);
  153.     force_string(tmp);
  154.     result = InDictionary(tmp->stptr);
  155.     free_temp(tmp);
  156.     return tmp_number((AWKNUM) result);
  157. }
  158.  
  159. NODE *do_log(NODE *tree)
  160. {
  161.     NODE *tmp;
  162.     /*double log();*/
  163.     double d, arg;
  164.  
  165.     get_one(tree, &tmp);
  166.     arg = (double) force_number(tmp);
  167.     if (arg < 0.0)
  168.         warning("log called with negative argument %g", arg);
  169.     d = log(arg);
  170.     free_temp(tmp);
  171.     return tmp_number((AWKNUM) d);
  172. }
  173.  
  174. /*
  175.  * Note that the output buffer cannot be static because sprintf may get
  176.  * called recursively by force_string.  Hence the wasteful alloca calls
  177.  */
  178.  
  179. /* %e and %f formats are not properly implemented.  Someone should fix them */
  180. NODE *do_sprintf(NODE *tree)
  181. {
  182. #define bchunk(s,l) if(l) {\
  183.     while((l)>ofre) {\
  184.       char *tmp;\
  185.       tmp=(char *)alloca(osiz*2);\
  186.       memcpy(tmp,obuf,olen);\
  187.       obuf=tmp;\
  188.       ofre+=osiz;\
  189.       osiz*=2;\
  190.     }\
  191.     memcpy(obuf+olen,s,(l));\
  192.     olen+=(l);\
  193.     ofre-=(l);\
  194.   }
  195.  
  196.     /* Is there space for something L big in the buffer? */
  197. #define chksize(l)  if((l)>ofre) {\
  198.     char *tmp;\
  199.     tmp=(char *)alloca(osiz*2);\
  200.     memcpy(tmp,obuf,olen);\
  201.     obuf=tmp;\
  202.     ofre+=osiz;\
  203.     osiz*=2;\
  204.   }
  205.  
  206.     /*
  207.      * Get the next arg to be formatted.  If we've run out of args,
  208.      * return "" (Null string)
  209.      */
  210. #define parse_next_arg() {\
  211.   if(!carg) arg= Nnull_string;\
  212.   else {\
  213.       get_one(carg,&arg);\
  214.     carg=carg->rnode;\
  215.   }\
  216.  }
  217.  
  218.     char *obuf;
  219.     short osiz, ofre, olen;
  220.     static char chbuf[] = "0123456789abcdef";
  221.     static char sp[] = " ";
  222.     char *s0, *s1;
  223.     short n0;
  224.     NODE *sfmt, *arg;
  225.     register NODE *carg;
  226.     long fw, prec, lj, alt, big;
  227.     long *cur;
  228.     long val;
  229. #ifdef sun386            /* Can't cast unsigned (short/long) from ptr->value */
  230.     long tmp_uval;        /* on 386i 4.0.1 C compiler -- it just hangs */
  231. #endif
  232.     unsigned long uval;
  233.     short sgn;
  234.     short base;
  235.     char cpbuf[30];        /* if we have numbers bigger than 30 */
  236.     char *cend = &cpbuf[30];/* chars, we lose, but seems unlikely */
  237.     char *cp;
  238.     char *fill;
  239.     double tmpval;
  240.     char *pr_str;
  241.     short ucasehex = 0;
  242.     extern char    *gcvt(double value, short digits, char *buff);
  243.  
  244.  
  245.     obuf = (char *) alloca(120);
  246.     osiz = 120;
  247.     ofre = osiz;
  248.     olen = 0;
  249.     get_one(tree, &sfmt);
  250.     sfmt = force_string(sfmt);
  251.     carg = tree->rnode;
  252.     for (s0 = s1 = sfmt->stptr, n0 = sfmt->stlen; n0-- > 0;) {
  253.         if (*s1 != '%') {
  254.             s1++;
  255.             continue;
  256.         }
  257.         bchunk(s0, (short)(s1 - s0));
  258.         s0 = s1;
  259.         cur = &fw;
  260.         fw = 0;
  261.         prec = 0;
  262.         lj = alt = big = 0;
  263.         fill = sp;
  264.         cp = cend;
  265.         s1++;
  266.  
  267. retry:
  268.         --n0;
  269.         switch (*s1++) {
  270.         case '%':
  271.             bchunk("%", 1);
  272.             s0 = s1;
  273.             break;
  274.  
  275.         case '0':
  276.             if (fill != sp || lj)
  277.                 goto lose;
  278.             if (cur == &fw)
  279.                 fill = "0";    /* FALL through */
  280.         case '1':
  281.         case '2':
  282.         case '3':
  283.         case '4':
  284.         case '5':
  285.         case '6':
  286.         case '7':
  287.         case '8':
  288.         case '9':
  289.             if (cur == 0)
  290.                 goto lose;
  291.             *cur = s1[-1] - '0';
  292.             while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
  293.                 --n0;
  294.                 *cur = *cur * 10 + *s1++ - '0';
  295.             }
  296.             goto retry;
  297. #ifdef not_yet
  298.         case ' ':        /* print ' ' or '-' */
  299.         case '+':        /* print '+' or '-' */
  300. #endif
  301.         case '-':
  302.             if (lj || fill != sp)
  303.                 goto lose;
  304.             lj++;
  305.             goto retry;
  306.         case '.':
  307.             if (cur != &fw)
  308.                 goto lose;
  309.             cur = ≺
  310.             goto retry;
  311.         case '#':
  312.             if (alt)
  313.                 goto lose;
  314.             alt++;
  315.             goto retry;
  316.         case 'l':
  317.             if (big)
  318.                 goto lose;
  319.             big++;
  320.             goto retry;
  321.         case 'c':
  322.             parse_next_arg();
  323.             if (arg->flags & NUMERIC) {
  324. #ifdef sun386
  325.                 tmp_uval = arg->numbr;
  326.                 uval= (unsigned long) tmp_uval;
  327. #else
  328.                 uval = (unsigned long) arg->numbr;
  329. #endif
  330.                 cpbuf[0] = uval;
  331.                 prec = 1;
  332.                 pr_str = cpbuf;
  333.                 goto dopr_string;
  334.             }
  335.             if (! prec)
  336.                 prec = 1;
  337.             else if (prec > arg->stlen)
  338.                 prec = arg->stlen;
  339.             pr_str = arg->stptr;
  340.             goto dopr_string;
  341.         case 's':
  342.             parse_next_arg();
  343.             arg = force_string(arg);
  344.             if (!prec || prec > arg->stlen)
  345.                 prec = arg->stlen;
  346.             pr_str = arg->stptr;
  347.  
  348.     dopr_string:
  349.             if (fw > prec && !lj) {
  350.                 while (fw > prec) {
  351.                     bchunk(sp, 1);
  352.                     fw--;
  353.                 }
  354.             }
  355.             bchunk(pr_str, (short) prec);
  356.             if (fw > prec) {
  357.                 while (fw > prec) {
  358.                     bchunk(sp, 1);
  359.                     fw--;
  360.                 }
  361.             }
  362.             s0 = s1;
  363.             free_temp(arg);
  364.             break;
  365.         case 'd':
  366.         case 'i':
  367.             parse_next_arg();
  368.             val = (long) force_number(arg);
  369.             free_temp(arg);
  370.             if (val < 0) {
  371.                 sgn = 1;
  372.                 val = -val;
  373.             } else
  374.                 sgn = 0;
  375.             do {
  376.                 *--cp = '0' + val % 10;
  377.                 val /= 10;
  378.             } while (val);
  379.             if (sgn)
  380.                 *--cp = '-';
  381.             if (prec > fw)
  382.                 fw = prec;
  383.             prec = cend - cp;
  384.             if (fw > prec && !lj) {
  385.                 if (fill != sp && *cp == '-') {
  386.                     bchunk(cp, 1);
  387.                     cp++;
  388.                     prec--;
  389.                     fw--;
  390.                 }
  391.                 while (fw > prec) {
  392.                     bchunk(fill, 1);
  393.                     fw--;
  394.                 }
  395.             }
  396.             bchunk(cp, (short) prec);
  397.             if (fw > prec) {
  398.                 while (fw > prec) {
  399.                     bchunk(fill, 1);
  400.                     fw--;
  401.                 }
  402.             }
  403.             s0 = s1;
  404.             break;
  405.         case 'u':
  406.             base = 10;
  407.             goto pr_unsigned;
  408.         case 'o':
  409.             base = 8;
  410.             goto pr_unsigned;
  411.         case 'X':
  412.             ucasehex = 1;
  413.         case 'x':
  414.             base = 16;
  415.             goto pr_unsigned;
  416.     pr_unsigned:
  417.             parse_next_arg();
  418.             uval = (unsigned long) force_number(arg);
  419.             free_temp(arg);
  420.             do {
  421.                 *--cp = chbuf[uval % base];
  422.                 if (ucasehex && isalpha(*cp))
  423.                     *cp = toupper(*cp);
  424.                 uval /= base;
  425.             } while (uval);
  426.             if (alt && (base == 8 || base == 16)) {
  427.                 if (base == 16) {
  428.                     if (ucasehex)
  429.                         *--cp = 'X';
  430.                     else
  431.                         *--cp = 'x';
  432.                 }
  433.                 *--cp = '0';
  434.             }
  435.             prec = cend - cp;
  436.             if (fw > prec && !lj) {
  437.                 while (fw > prec) {
  438.                     bchunk(fill, 1);
  439.                     fw--;
  440.                 }
  441.             }
  442.             bchunk(cp, (short) prec);
  443.             if (fw > prec) {
  444.                 while (fw > prec) {
  445.                     bchunk(fill, 1);
  446.                     fw--;
  447.                 }
  448.             }
  449.             s0 = s1;
  450.             break;
  451.         case 'g':
  452.             parse_next_arg();
  453.             tmpval = force_number(arg);
  454.             free_temp(arg);
  455.             if (prec == 0)
  456.                 prec = 13;
  457.             (void) gcvt(tmpval, (short) prec, cpbuf);
  458.             prec = strlen(cpbuf);
  459.             cp = cpbuf;
  460.             if (fw > prec && !lj) {
  461.                 if (fill != sp && *cp == '-') {
  462.                     bchunk(cp, 1);
  463.                     cp++;
  464.                     prec--;
  465.                 }    /* Deal with .5 as 0.5 */
  466.                 if (fill == sp && *cp == '.') {
  467.                     --fw;
  468.                     while (--fw >= prec) {
  469.                         bchunk(fill, 1);
  470.                     }
  471.                     bchunk("0", 1);
  472.                 } else
  473.                     while (fw-- > prec)
  474.                         bchunk(fill, 1);
  475.             } else {/* Turn .5 into 0.5 */
  476.                 /* FOO */
  477.                 if (*cp == '.' && fill == sp) {
  478.                     bchunk("0", 1);
  479.                     --fw;
  480.                 }
  481.             }
  482.             bchunk(cp, (short) prec);
  483.             if (fw > prec)
  484.                 while (fw-- > prec)
  485.                     bchunk(fill, 1);
  486.             s0 = s1;
  487.             break;
  488.         case 'f':
  489.             parse_next_arg();
  490.             tmpval = force_number(arg);
  491.             free_temp(arg);
  492.             chksize(fw + prec + 5);    /* 5==slop */
  493.  
  494.             cp = cpbuf;
  495.             *cp++ = '%';
  496.             if (lj)
  497.                 *cp++ = '-';
  498.             if (fill != sp)
  499.                 *cp++ = '0';
  500.             if (cur != &fw) {
  501.                 (void) strcpy(cp, "*.*f");
  502.                 (void) sprintf(obuf + olen, cpbuf, (short) fw, (short) prec, (double) tmpval);
  503.             } else {
  504.                 (void) strcpy(cp, "*f");
  505.                 (void) sprintf(obuf + olen, cpbuf, (short) fw, (double) tmpval);
  506.             }
  507.             ofre -= strlen(obuf + olen);
  508.             olen += strlen(obuf + olen);    /* There may be nulls */
  509.             s0 = s1;
  510.             break;
  511.         case 'e':
  512.             parse_next_arg();
  513.             tmpval = force_number(arg);
  514.             free_temp(arg);
  515.             chksize(fw + prec + 5);    /* 5==slop */
  516.             cp = cpbuf;
  517.             *cp++ = '%';
  518.             if (lj)
  519.                 *cp++ = '-';
  520.             if (fill != sp)
  521.                 *cp++ = '0';
  522.             if (cur != &fw) {
  523.                 (void) strcpy(cp, "*.*e");
  524.                 (void) sprintf(obuf + olen, cpbuf, (short) fw, (short) prec, (double) tmpval);
  525.             } else {
  526.                 (void) strcpy(cp, "*e");
  527.                 (void) sprintf(obuf + olen, cpbuf, (short) fw, (double) tmpval);
  528.             }
  529.             ofre -= strlen(obuf + olen);
  530.             olen += strlen(obuf + olen);    /* There may be nulls */
  531.             s0 = s1;
  532.             break;
  533.  
  534.         default:
  535.     lose:
  536.             break;
  537.         }
  538.     }
  539.     bchunk(s0, (short)(s1 - s0));
  540.     free_temp(sfmt);
  541.     return tmp_string(obuf, olen);
  542. }
  543.  
  544. void do_printf(NODE *tree)
  545. {
  546.     struct redirect *rp = NULL;
  547.     register FILE *fp = stdout;
  548.     short errflg = 0;        /* not used, sigh */
  549.  
  550.     if (tree->rnode) {
  551.         rp = redirect(tree->rnode, &errflg);
  552.         if (rp)
  553.             fp = rp->fp;
  554.     }
  555.     if (fp)
  556.         print_simple(do_sprintf(tree->lnode), fp);
  557.     if (rp && (rp->flag & RED_NOBUF))
  558.         fflush(fp);
  559. }
  560.  
  561. NODE *do_sqrt(NODE *tree)
  562. {
  563.     NODE *tmp;
  564.     /*double sqrt();*/
  565.     double d, arg;
  566.  
  567.     get_one(tree, &tmp);
  568.     arg = (double) force_number(tmp);
  569.     if (arg < 0.0)
  570.         warning("sqrt called with negative argument %g", arg);
  571.     d = sqrt(arg);
  572.     free_temp(tmp);
  573.     return tmp_number((AWKNUM) d);
  574. }
  575.  
  576. NODE *do_substr(NODE *tree)
  577. {
  578.     NODE *t1, *t2, *t3;
  579.     NODE *r;
  580.     register short indx, length;
  581.  
  582.     t1 = t2 = t3 = NULL;
  583.     length = -1;
  584.     if (get_three(tree, &t1, &t2, &t3) == 3)
  585.         length = (short) force_number(t3);
  586.     indx = (short) force_number(t2) - 1;
  587.     t1 = force_string(t1);
  588.     if (length == -1)
  589.         length = t1->stlen;
  590.     if (indx < 0)
  591.         indx = 0;
  592.     if (indx >= t1->stlen || length <= 0) {
  593.         if (t3)
  594.             free_temp(t3);
  595.         free_temp(t2);
  596.         free_temp(t1);
  597.         return Nnull_string;
  598.     }
  599.     if (indx + length > t1->stlen)
  600.         length = t1->stlen - indx;
  601.     if (t3)
  602.         free_temp(t3);
  603.     free_temp(t2);
  604.     r =  tmp_string(t1->stptr + indx, length);
  605.     free_temp(t1);
  606.     return r;
  607. }
  608.  
  609. NODE *do_system(NODE *tree)
  610. {
  611. #if defined(unix) || defined(MSDOS) /* || defined(gnu) */
  612.     NODE *tmp;
  613.     short ret;
  614.  
  615.     (void) flush_io ();    /* so output is synchronous with gawk's */
  616.     get_one(tree, &tmp);
  617.     ret = system(force_string(tmp)->stptr);
  618.     ret = (ret >> 8) & 0xff;
  619.     free_temp(tmp);
  620.     return tmp_number((AWKNUM) ret);
  621. #else
  622.     fatal("the \"system\" function is not supported.");
  623.     /* NOTREACHED */
  624. #endif
  625. }
  626.  
  627. void do_print(register NODE *tree)
  628. {
  629.     struct redirect *rp = NULL;
  630.     register FILE *fp = stdout;
  631.     short errflg = 0;        /* not used, sigh */
  632.  
  633.     if (tree->rnode) {
  634.         rp = redirect(tree->rnode, &errflg);
  635.         if (rp)
  636.             fp = rp->fp;
  637.     }
  638.     if (!fp)
  639.         return;
  640.     tree = tree->lnode;
  641.     if (!tree)
  642.         tree = WHOLELINE;
  643.     if (tree->type != Node_expression_list) {
  644.         if (!(tree->flags & STR))
  645.             cant_happen();
  646.         print_simple(tree, fp);
  647.     } else {
  648.         while (tree) {
  649.             print_simple(force_string(tree_eval(tree->lnode)), fp);
  650.             tree = tree->rnode;
  651.             if (tree)
  652.                 print_simple(OFS_node->var_value, fp);
  653.         }
  654.     }
  655.     print_simple(ORS_node->var_value, fp);
  656.     if (rp && (rp->flag & RED_NOBUF))
  657.         fflush(fp);
  658. }
  659.  
  660. NODE *do_tolower(NODE *tree)
  661. {
  662.     NODE *t1, *t2;
  663.     register char *cp, *cp2;
  664.  
  665.     get_one(tree, &t1);
  666.     t1 = force_string(t1);
  667.     t2 = tmp_string(t1->stptr, t1->stlen);
  668.     for (cp = t2->stptr, cp2 = t2->stptr + t2->stlen; cp < cp2; cp++)
  669.         if (isupper(*cp))
  670.             *cp = tolower(*cp);
  671.     free_temp(t1);
  672.     return t2;
  673. }
  674.  
  675. NODE *do_toupper(NODE *tree)
  676. {
  677.     NODE *t1, *t2;
  678.     register char *cp;
  679.  
  680.     get_one(tree, &t1);
  681.     t1 = force_string(t1);
  682.     t2 = tmp_string(t1->stptr, t1->stlen);
  683.     for (cp = t2->stptr; cp < t2->stptr + t2->stlen; cp++)
  684.         if (islower(*cp))
  685.             *cp = toupper(*cp);
  686.     free_temp(t1);
  687.     return t2;
  688. }
  689.  
  690. /*
  691.  * Get the arguments to functions.  No function cares if you give it too many
  692.  * args (they're ignored).  Only a few fuctions complain about being given
  693.  * too few args.  The rest have defaults.
  694.  */
  695.  
  696. static void get_one(NODE *tree, NODE **res)
  697. {
  698.     if (!tree) {
  699.         *res = WHOLELINE;
  700.         return;
  701.     }
  702.     *res = tree_eval(tree->lnode);
  703. }
  704.  
  705. static void get_two(NODE *tree, NODE **res1, NODE **res2)
  706. {
  707.     if (!tree) {
  708.         *res1 = WHOLELINE;
  709.         return;
  710.     }
  711.     *res1 = tree_eval(tree->lnode);
  712.     if (!tree->rnode)
  713.         return;
  714.     tree = tree->rnode;
  715.     *res2 = tree_eval(tree->lnode);
  716. }
  717.  
  718. static short get_three(NODE *tree, NODE **res1, NODE **res2, NODE **res3)
  719. {
  720.     if (!tree) {
  721.         *res1 = WHOLELINE;
  722.         return 0;
  723.     }
  724.     *res1 = tree_eval(tree->lnode);
  725.     if (!tree->rnode)
  726.         return 1;
  727.     tree = tree->rnode;
  728.     *res2 = tree_eval(tree->lnode);
  729.     if (!tree->rnode)
  730.         return 2;
  731.     tree = tree->rnode;
  732.     *res3 = tree_eval(tree->lnode);
  733.     return 3;
  734. }
  735.  
  736. short a_get_three(NODE *tree, NODE **res1, NODE **res2, NODE **res3)
  737. {
  738.     if (!tree) {
  739.         *res1 = WHOLELINE;
  740.         return 0;
  741.     }
  742.     *res1 = tree_eval(tree->lnode);
  743.     if (!tree->rnode)
  744.         return 1;
  745.     tree = tree->rnode;
  746.     *res2 = tree->lnode;
  747.     if (!tree->rnode)
  748.         return 2;
  749.     tree = tree->rnode;
  750.     *res3 = tree_eval(tree->lnode);
  751.     return 3;
  752. }
  753.  
  754. void print_simple(NODE *tree, FILE *fp)
  755. {
  756.     if (fwrite(tree->stptr, sizeof(char), tree->stlen, fp) != tree->stlen)
  757.         warning("fwrite: %s", strerror(errno));
  758.     free_temp(tree);
  759. }
  760.  
  761. NODE *do_atan2(NODE *tree)
  762. {
  763.     NODE *t1, *t2;
  764.     /*extern double atan2();*/
  765.     double d1, d2;
  766.  
  767.     get_two(tree, &t1, &t2);
  768.     d1 = force_number(t1);
  769.     d2 = force_number(t2);
  770.     free_temp(t1);
  771.     free_temp(t2);
  772.     return tmp_number((AWKNUM) atan2(d1, d2));
  773. }
  774.  
  775. NODE *do_sin(NODE *tree)
  776. {
  777.     NODE *tmp;
  778.     /*extern double sin();*/
  779.     double d;
  780.  
  781.     get_one(tree, &tmp);
  782.     d = sin((double)force_number(tmp));
  783.     free_temp(tmp);
  784.     return tmp_number((AWKNUM) d);
  785. }
  786.  
  787. NODE *do_cos(NODE *tree)
  788. {
  789.     NODE *tmp;
  790.     /*extern double cos();*/
  791.     double d;
  792.  
  793.     get_one(tree, &tmp);
  794.     d = cos((double)force_number(tmp));
  795.     free_temp(tmp);
  796.     return tmp_number((AWKNUM) d);
  797. }
  798.  
  799. static short firstrand = 1;
  800. static char state[256];
  801.  
  802. #define    MAXLONG    2147483647    /* maximum value for long short */
  803.  
  804. /* ARGSUSED */
  805. NODE *do_rand(NODE *tree)
  806. {
  807.     if (firstrand) {
  808.         (void) initstate((unsigned) 1, state, sizeof state);
  809.         srandom(1);
  810.         firstrand = 0;
  811.     }
  812.     return tmp_number((AWKNUM) random() / MAXLONG);
  813. }
  814.  
  815. NODE *do_srand(NODE *tree)
  816. {
  817.     NODE *tmp;
  818.     static unsigned long save_seed = 1;
  819.     long ret = save_seed;    /* SVR4 awk srand returns previous seed */
  820.     /*extern long time();*/
  821.  
  822.     if (firstrand)
  823.         (void) initstate((unsigned) 1, state, sizeof state);
  824.     else
  825.         (void) setstate(state);
  826.  
  827.     if (!tree)
  828.         srandom((short) (save_seed = time((unsigned long *) 0)));
  829.     else {
  830.         get_one(tree, &tmp);
  831.         srandom((short) (save_seed = (long) force_number(tmp)));
  832.         free_temp(tmp);
  833.     }
  834.     firstrand = 0;
  835.     return tmp_number((AWKNUM) ret);
  836. }
  837.  
  838. NODE *do_match(NODE *tree)
  839. {
  840.     NODE *t1;
  841.     short rstart;
  842.     struct re_registers reregs;
  843.     struct re_pattern_buffer *rp;
  844.     short need_to_free = 0;
  845.  
  846.     t1 = force_string(tree_eval(tree->lnode));
  847.     tree = tree->rnode;
  848.     if (tree == NULL || tree->lnode == NULL)
  849.         fatal("match called with only one argument");
  850.     tree = tree->lnode;
  851.     if (tree->type == Node_regex) {
  852.         rp = tree->rereg;
  853.         if (/*!strict && */ ((IGNORECASE_node->var_value->numbr != 0)
  854.             ^ (tree->re_case != 0))) {
  855.             /* recompile since case sensitivity differs */
  856.             rp = tree->rereg =
  857.                 mk_re_parse(tree->re_text,
  858.                 (IGNORECASE_node->var_value->numbr != 0));
  859.             tree->re_case =
  860.                 (IGNORECASE_node->var_value->numbr != 0);
  861.         }
  862.     } else {
  863.         need_to_free = 1;
  864.         rp = make_regexp(force_string(tree_eval(tree)),
  865.                 (IGNORECASE_node->var_value->numbr != 0));
  866.         if (rp == NULL)
  867.             cant_happen();
  868.     }
  869.     rstart = re_search(rp, t1->stptr, t1->stlen, 0, t1->stlen, &reregs);
  870.     free_temp(t1);
  871.     if (rstart >= 0) {
  872.         rstart++;    /* 1-based indexing */
  873.         /* RSTART set to rstart below */
  874.         assign_number(& RLENGTH_node->var_value,
  875.             (AWKNUM) (reregs.end[0] - reregs.start[0]));
  876.     } else {
  877.         /*
  878.          * Match failed. Set RSTART to 0, RLENGTH to -1.
  879.          * Return the value of RSTART.
  880.          */
  881.         rstart = 0;    /* used as return value */
  882.         assign_number(& RLENGTH_node->var_value, (AWKNUM) -1.0);
  883.     }
  884.     assign_number(& RSTART_node->var_value, (AWKNUM) rstart);
  885.     if (need_to_free) {
  886.         free(rp->buffer);
  887.         free(rp->fastmap);
  888.         free((char *) rp);
  889.     }
  890.     return tmp_number((AWKNUM) rstart);
  891. }
  892.  
  893.  
  894. static NODE *sub_common(NODE *tree, short global)
  895. {
  896.     register short len;
  897.     register char *scan;
  898.     register char *bp, *cp;
  899.     short search_start = 0;
  900.     short match_length;
  901.     short matches = 0;
  902.     char *buf;
  903.     struct re_pattern_buffer *rp;
  904.     NODE *s;        /* subst. pattern */
  905.     NODE *t;        /* string to make sub. in; $0 if none given */
  906.     struct re_registers reregs;
  907.     unsigned short saveflags;
  908.     NODE *tmp;
  909.     NODE **lhs;
  910.     char *lastbuf;
  911.     short need_to_free = 0;
  912.     char theTag;
  913.     short     regForTag;
  914.     
  915.     if (tree == NULL)
  916.         fatal("sub or gsub called with 0 arguments");
  917.     tmp = tree->lnode;
  918.     if (tmp->type == Node_regex) {
  919.         rp = tmp->rereg;
  920.         if (/*! strict && */ ((IGNORECASE_node->var_value->numbr != 0)
  921.             ^ (tmp->re_case != 0))) {
  922.             /* recompile since case sensitivity differs */
  923.             rp = tmp->rereg =
  924.                 mk_re_parse(tmp->re_text,
  925.                 (IGNORECASE_node->var_value->numbr != 0));
  926.             tmp->re_case = (IGNORECASE_node->var_value->numbr != 0);
  927.         }
  928.     } else {
  929.         need_to_free = 1;
  930.         
  931.         rp = make_regexp(force_string(tree_eval(tmp)),
  932.                 (IGNORECASE_node->var_value->numbr != 0));
  933.         if (rp == NULL)
  934.             cant_happen();
  935.     }
  936.     tree = tree->rnode;
  937.     if (tree == NULL)
  938.         fatal("sub or gsub called with only 1 argument");
  939.     s = force_string(tree_eval(tree->lnode));
  940.     tree = tree->rnode;
  941.     deref = 0;
  942.     field_num = -1;
  943.     if (tree == NULL) {
  944.         t = node0_valid ? fields_arr[0] : *get_field(0, 0);
  945.         lhs = &fields_arr[0];
  946.         field_num = 0;
  947.         deref = t;
  948.     } else {
  949.         
  950.         t = tree->lnode;
  951.         lhs = get_lhs(t, 1);
  952.         t = force_string(tree_eval(t));
  953.     }
  954.     /*
  955.      * create a private copy of the string
  956.      */
  957.     if (t->stref > 1 || (t->flags & PERM)) {
  958.         saveflags = t->flags;
  959.         t->flags &= ~MALLOC; /* MALLOC is defined inside NODE struct */
  960.         tmp = dupnode(t);
  961.         t->flags = saveflags;
  962.         do_deref();
  963.         t = tmp;
  964.         if (lhs)
  965.             *lhs = tmp;
  966.     }
  967.     lastbuf = t->stptr;
  968.     do {
  969.         if (re_search(rp, t->stptr, t->stlen, search_start,
  970.             t->stlen-search_start, &reregs) == -1
  971.             || reregs.start[0] == reregs.end[0])
  972.             break;
  973.         matches++;
  974.         /*
  975.          * first, make a pass through the sub. pattern, to calculate
  976.          * the length of the string after substitution
  977.          */
  978.         match_length = reregs.end[0] - reregs.start[0];
  979.         len = t->stlen - match_length;
  980.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  981.             if (*scan == '&')
  982.                 len += match_length;
  983.             else if (*scan == '\\' && *(scan+1) == '&')
  984.                 {
  985.                 scan++;
  986.                 len++;
  987.                 }
  988.             else if (*scan == '\\' && (theTag = *(scan+1)) >= '1'
  989.                     && theTag <= '9')
  990.                 {
  991.                 scan++;
  992.                 regForTag = theTag - '0';
  993.                 len += reregs.end[regForTag] - reregs.start[regForTag];
  994.                 }
  995.             else
  996.                 len++;
  997.         emalloc(buf, char *, len + 1, "do_sub");
  998.         bp = buf;
  999.  
  1000.         /*
  1001.          * now, create the result, copying in parts of the original
  1002.          * string
  1003.          */
  1004.         for (scan = t->stptr; scan < t->stptr + reregs.start[0]; scan++)
  1005.             *bp++ = *scan;
  1006.         for (scan = s->stptr; scan < s->stptr + s->stlen; scan++)
  1007.             if (*scan == '&')
  1008.                 for (cp = t->stptr + reregs.start[0];
  1009.                      cp < t->stptr + reregs.end[0]; cp++)
  1010.                     *bp++ = *cp;
  1011.             else if (*scan == '\\' && *(scan+1) == '&')
  1012.                 {
  1013.                 scan++;
  1014.                 *bp++ = *scan;
  1015.                 }
  1016.             else if (*scan == '\\' && (theTag = *(scan+1)) >= '1'
  1017.                     && theTag <= '9')
  1018.                 {
  1019.                 scan++;
  1020.                 regForTag = theTag - '0';
  1021.                 for (cp = t->stptr + reregs.start[regForTag];
  1022.                      cp < t->stptr + reregs.end[regForTag]; cp++)
  1023.                     *bp++ = *cp;
  1024.                 }
  1025.             else
  1026.                 *bp++ = *scan;
  1027.         search_start = bp - buf;
  1028.         for (scan = t->stptr + reregs.end[0];
  1029.              scan < t->stptr + t->stlen; scan++)
  1030.             *bp++ = *scan;
  1031.         *bp = '\0';
  1032.         free(lastbuf);
  1033.         t->stptr = buf;
  1034.         lastbuf = buf;
  1035.         t->stlen = len;
  1036.     } while (global && search_start < t->stlen);
  1037.  
  1038.     free_temp(s);
  1039.     if (need_to_free) {
  1040.         free(rp->buffer);
  1041.         free(rp->fastmap);
  1042.         free((char *) rp);
  1043.     }
  1044.     if (matches > 0) {
  1045.         if (field_num == 0)
  1046.             set_record(fields_arr[0]->stptr, fields_arr[0]->stlen);
  1047.         t->flags &= ~(NUM|NUMERIC);
  1048.     }
  1049.     field_num = -1;
  1050.     return tmp_number((AWKNUM) matches);
  1051. }
  1052.  
  1053. NODE *do_gsub(NODE *tree)
  1054. {
  1055.     return sub_common(tree, 1);
  1056. }
  1057.  
  1058. NODE *do_sub(NODE *tree)
  1059. {
  1060.     return sub_common(tree, 0);
  1061. }
  1062.  
  1063.